module Forwarding (

    input               clock,
    input               reset,

    //Fetch
    output              fw_if_id_stall,

    //Decode
    input        [4:0]  id_fw_regdest,
    input               id_fw_load,
    input        [4:0]  id_fw_addra,
    input        [4:0]  id_fw_addrb,
    input       [31:0]  id_fw_rega,
    input       [31:0]  id_fw_regb,
    output reg  [31:0]  fw_id_rega,
    output reg  [31:0]  fw_id_regb,

    //Execute
    input       [31:0]  ex_fw_wbvalue,
    input               ex_fw_writereg,

    //Memory
    input       [31:0]  mem_fw_wbvalue, 
    input               mem_fw_writereg,

    //Writeback
    input       [31:0]  wb_fw_wbvalue,
    input               wb_fw_writereg
    
    );
    
    // Four positions queue that recieves the destination address always
    // a new instruction goes through the decode stage
    reg [4:0] TableFW [3:0] ;

    reg ex_fw_load;

    // If the instruction executing is a load and there is any data
    // dependency a stall is introduced
    assign fw_if_id_stall = (ex_fw_load 
        && ((id_fw_addra == TableFW [1])
        || (id_fw_addrb == TableFW [1]))) ? 1'b1 : 1'b0;
    
    always @(negedge clock or negedge reset) begin
        
        if (reset) begin
            // Reset all registers from this module
            TableFW [0] <= 5'b00000;
            TableFW [1] <= 5'b00000;
            TableFW [2] <= 5'b00000;
            TableFW [3] <= 5'b00000;
            fw_id_rega  <= 32'b0;
            fw_id_regb  <= 32'b0;
            ex_fw_load  <= 1'b0;
      	end
    	else begin
            // Forwarding table TableFW [3] is the oldest address
            TableFW [0] <= id_fw_regdest;   // Destination of instruction in ID
            TableFW [1] <= TableFW [0];     // Destination of instruction in EX
            TableFW [2] <= TableFW [1];     // Destination of instruction in MEM
            TableFW [3] <= TableFW [2];     // Destination of instruction in WB
            
            // If the decoded instruction is a load, the execution instruction 
            // will be a load on the next cycle
            ex_fw_load <= id_fw_load;

            // Forwards the A register. Checks from the closest to farthest
            // stage if there is any data dependency and if this value will be
            // writen in the WB stage.
            if (TableFW [1] == id_fw_addra && ex_fw_writereg) begin
                //Execute
        		fw_id_rega <= ex_fw_wbvalue;
            end
            else begin
                if (TableFW [2] == id_fw_addra && mem_fw_writereg) begin
                    //Memory
                    fw_id_rega <= mem_fw_wbvalue;
                end
                else begin
                    if (TableFW [3] == id_fw_addra && wb_fw_writereg) begin
                        //Writeback
                        fw_id_rega <= wb_fw_wbvalue;
                    end
                    else begin
                        // Get value from register bank
                        fw_id_rega <= id_fw_rega;
                    end
                end
            end

            // Forwards the B register. Checks from the closest to farthest
            // stage if there is any data dependency and if this value will be
            // writen in the WB stage.
            if (TableFW [1] == id_fw_addrb && ex_fw_writereg) begin
                //Execute
                fw_id_regb <= ex_fw_wbvalue;
            end
            else begin
                if (TableFW [2] == id_fw_addrb && mem_fw_writereg) begin
                    //Memory
                    fw_id_regb <= mem_fw_wbvalue;
                end
                else begin
                    if (TableFW [3] == id_fw_addrb && wb_fw_writereg) begin
                        //Writeback
                        fw_id_regb <= wb_fw_wbvalue;
                    end
                    else begin
                        // Get value from register bank
                        fw_id_regb <= id_fw_regb;
                    end
                end
            end
    	end

     end

endmodule
